import sys
import os, os.path
+import errno
import resource
import re
import types
def __init__(self,msg):
self.message = msg
def __str__(self):
- return 'Error Parsing PCI Device Info: '+self.message
+ return self.message
class PciDeviceAssignmentError(Exception):
def __init__(self,msg):
os.close(fd)
def detect_dev_info(self):
- class_dev = self.pci_conf_read16(PCI_CLASS_DEVICE)
+ try:
+ class_dev = self.pci_conf_read16(PCI_CLASS_DEVICE)
+ except OSError, (err, strerr):
+ if err == errno.ENOENT:
+ strerr = "the device doesn't exist?"
+ raise PciDeviceParseError('%s: %s' %\
+ (self.name, strerr))
pos = self.find_cap_offset(PCI_CAP_ID_EXP)
if class_dev == PCI_CLASS_BRIDGE_PCI:
if pos == 0:
', but it is not owned by pciback or pci-stub.'
raise PciDeviceAssignmentError(err_msg % (pci_dev, self.name))
- def do_FLR(self):
+ def do_FLR(self, is_hvm):
""" Perform FLR (Functional Level Reset) for the device.
"""
if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
self.do_FLR_for_integrated_device()
else:
funcs = self.find_all_the_multi_functions()
+
+ if not is_hvm and (len(funcs) > 1):
+ return
+
self.devs_check_driver(funcs)
parent = pci_dict_to_bdf_str(self.find_parent())
# Remove the element 0 which is a bridge
target_bus = devs[0]
del devs[0]
+
+ if not is_hvm and (len(devs) > 1):
+ return
+
self.devs_check_driver(devs)
# Do Secondary Bus Reset.
log.exception("Unable to recreate domain")
try:
xc.domain_pause(domid)
- XendDomainInfo.do_FLR(domid)
+ XendDomainInfo.do_FLR(domid, dom['hvm'])
xc.domain_destroy(domid)
except:
log.exception("Hard destruction of domain failed: %d" %
else:
try:
xc.domain_pause(int(domid))
- XendDomainInfo.do_FLR(int(domid))
+ dom = self.domains[int(domid)]
+ XendDomainInfo.do_FLR(int(domid), dom.info.is_hvm())
val = xc.domain_destroy(int(domid))
except ValueError:
raise XendInvalidDomain(domid)
get_assigned_pci_devices, get_all_assigned_pci_devices
-def do_FLR(domid):
+def do_FLR(domid, is_hvm):
dev_str_list = get_assigned_pci_devices(domid)
for dev_str in dev_str_list:
except Exception, e:
raise VmError("pci: failed to locate device and "+
"parse it's resources - "+str(e))
- dev.do_FLR()
+ dev.do_FLR(is_hvm)
class XendDomainInfo:
"""An object represents a domain.
# Test whether the device is owned by pciback. For instance, we can't
# hotplug a device being used by Dom0 itself to an HVM guest.
- from xen.xend.server.pciif import PciDevice, parse_pci_name
try:
pci_device = PciDevice(new_dev)
except Exception, e:
raise VmError("pci: failed to locate device and "+
- "parse it's resources - "+str(e))
+ "parse its resources - "+str(e))
if pci_device.driver!='pciback' and pci_device.driver!='pci-stub':
- raise VmError(("pci: PCI Backend does not own device "+ \
- "%s\n"+ \
- "See the pciback.hide kernel "+ \
- "command-line parameter or\n"+ \
- "bind your slot/device to the PCI backend using sysfs" \
- )%(pci_device.name))
+ raise VmError(("pci: PCI Backend and pci-stub don't own device %s")\
+ %pci_device.name)
# Check non-page-aligned MMIO BAR.
if pci_device.has_non_page_aligned_bar and arch.type != "ia64":
pci_device = PciDevice(pci_dev)
except Exception, e:
raise VmError("pci: failed to locate device and "+
- "parse it's resources - "+str(e))
+ "parse its resources - "+str(e))
coassignment_list = pci_device.find_coassigned_devices()
coassignment_list.remove(pci_device.name)
assigned_pci_device_str_list = self._get_assigned_pci_devices()
pci = map(lambda x: x[0:4], pci) # strip options
pci_str = str(pci)
+ # This test is done for both pv and hvm guest.
+ for p in pci:
+ pci_name = '%04x:%02x:%02x.%x' % \
+ (parse_hex(p[0]), parse_hex(p[1]), parse_hex(p[2]), parse_hex(p[3]))
+ try:
+ pci_device = PciDevice(parse_pci_name(pci_name))
+ except Exception, e:
+ raise VmError("pci: failed to locate device and "+
+ "parse its resources - "+str(e))
+ if pci_device.driver!='pciback' and pci_device.driver!='pci-stub':
+ raise VmError(("pci: PCI Backend and pci-stub don't own device %s")\
+ %pci_device.name)
+ if pci_name in get_all_assigned_pci_devices():
+ raise VmError("failed to assign device %s that has"
+ " already been assigned to other domain." % pci_name)
+
if hvm and pci_str != '':
bdf = xc.test_assign_device(0, pci_str)
if bdf != 0:
devfn = (bdf >> 8) & 0xff
dev = (devfn >> 3) & 0x1f
func = devfn & 0x7
- raise VmError("failed to assign device(%x:%x.%x): maybe it has"
+ raise VmError("failed to assign device %02x:%02x.%x: maybe it has"
" already been assigned to other domain, or maybe"
" it doesn't exist." % (bus, dev, func))
- # This test is done for both pv and hvm guest.
- for p in pci:
- pci_name = '%04x:%02x:%02x.%x' % \
- (parse_hex(p[0]), parse_hex(p[1]), parse_hex(p[2]), parse_hex(p[3]))
- if pci_name in get_all_assigned_pci_devices():
- raise VmError("failed to assign device %s that has"
- " already been assigned to other domain." % pci_name)
-
# register the domain in the list
from xen.xend import XendDomain
XendDomain.instance().add_domain(self)
try:
xc.domain_destroy_hook(self.domid)
xc.domain_pause(self.domid)
- do_FLR(self.domid)
+ do_FLR(self.domid, self.info.is_hvm())
xc.domain_destroy(self.domid)
for state in DOM_STATES_OLD:
self.info[state] = 0
dev = PciDevice(pci_dev)
except Exception, e:
raise VmError("pci: failed to locate device and "+
- "parse it's resources - "+str(e))
+ "parse its resources - "+str(e))
if dev.driver!='pciback' and dev.driver!='pci-stub':
raise VmError(("pci: PCI Backend and pci-stub don't own "+ \
dev = PciDevice(pci_dev)
except Exception, e:
raise VmError("pci: failed to locate device and "+
- "parse it's resources - "+str(e))
+ "parse its resources - "+str(e))
if (dev.dev_type == DEV_TYPE_PCIe_ENDPOINT) and not dev.pcie_flr:
if dev.bus == 0:
# We cope with this case by using the Dstate transition
' method or some vendor specific methods if available.'
log.warn(err_msg % dev.name)
else:
+ if not self.vm.info.is_hvm():
+ continue
+
funcs = dev.find_all_the_multi_functions()
dev.devs_check_driver(funcs)
for f in funcs:
' specific methods if available.'
log.warn(err_msg % dev.name)
else:
+ if not self.vm.info.is_hvm():
+ continue
+
# All devices behind the uppermost PCI/PCI-X bridge must be\
# co-assigned to the same guest.
devs_str = dev.find_coassigned_pci_devices(True)
dev = PciDevice(pci_dev)
except Exception, e:
raise VmError("pci: failed to locate device and "+
- "parse it's resources - "+str(e))
+ "parse its resources - "+str(e))
if dev.driver!='pciback' and dev.driver!='pci-stub':
raise VmError(("pci: PCI Backend and pci-stub don't own device "+ \
# Need to do FLR here before deassign device in order to terminate
# DMA transaction, etc
- dev.do_FLR()
+ dev.do_FLR(self.vm.info.is_hvm())
bdf = xc.deassign_device(fe_domid, pci_dict_to_xc_str(pci_dev))
pci_str = pci_dict_to_bdf_str(pci_dev)
(dom, dev) = parse_pci_configuration(params, config_pci_opts)
+ attached = attached_pci_dict(dom)
+
+ attached_dev = map(lambda x: find_attached(attached, x, False), dev)
+
head_dev = dev.pop(0)
xm_pci_attach_one(dom, head_dev)
arg_check(args, 'network-detach', 2, 3)
detach(args, 'vif')
-def find_attached(attached, key):
+def find_attached(attached, key, detaching):
l = filter(lambda dev: pci_dict_cmp(dev, key), attached)
- if len(l) == 0:
- raise OptionError("pci: device is not attached: " +
- pci_dict_to_bdf_str(key))
-
- # There shouldn't ever be more than one match,
- # but perhaps an exception should be thrown if there is
- return l[0]
+ if detaching:
+ if len(l) == 0:
+ raise OptionError("pci: device %s is not attached!" %\
+ pci_dict_to_bdf_str(key))
+ # There shouldn't ever be more than one match,
+ # but perhaps an exception should be thrown if there is
+ return l[0]
+ else:
+ if len(l) == 1:
+ raise OptionError("pci: device %s has been attached! " %\
+ pci_dict_to_bdf_str(key))
+ return None
def find_attached_devfn(attached, key):
- pci_dev = find_attached(attached, key)
+ pci_dev = find_attached(attached, key, True)
return pci_dev['vdevfn']
def xm_pci_detach(args):
(dom, dev) = parse_pci_configuration(args)
attached = attached_pci_dict(dom)
- attached_dev = map(lambda x: find_attached(attached, x), dev)
+ attached_dev = map(lambda x: find_attached(attached, x, True), dev)
def f(pci_dev):
vdevfn = int(pci_dev['vdevfn'], 16)